using System;
using System.Collections.Generic;
using System.Text;
using org.ngwt.user.server.rpc;
using org.ngwt.user.client.rpc;

namespace org.ngwt.user.server.rpc.impl
{
    /**
     * Standard implementation of a {@link SerializationPolicy}.
     */
    public class StandardSerializationPolicy : SerializationPolicy
    {
        private Dictionary<Type, Boolean> whitelist;

        /**
         * Constructs a {@link SerializationPolicy} from a {@link Map}.
         */
        public StandardSerializationPolicy(Dictionary<Type, Boolean> whitelist)
        {
            if (whitelist == null) {
                throw new NullReferenceException("whitelist");
            }

            this.whitelist = whitelist;
        }

        /*
         * (non-Javadoc)
         * 
         * @see com.google.gwt.user.server.rpc.SerializationPolicy#shouldDerializeFields(java.lang.String)
         */
        public override Boolean shouldDeserializeFields(Type clazz) 
        {
            return isFieldSerializable(clazz);
        }

      /*
       * (non-Javadoc)
       * 
       * @see com.google.gwt.user.server.rpc.SerializationPolicy#shouldSerializeFields(java.lang.String)
       */
      public override Boolean shouldSerializeFields(Type clazz) 
      {
        return isFieldSerializable(clazz);
      }

      /*
       * (non-Javadoc)
       * 
       * @see com.google.gwt.user.server.rpc.SerializationPolicy#validateDeserialize(java.lang.String)
       */
      public override void validateDeserialize(Type clazz)
      {
        if (!isInstantiable(clazz)) {
          throw new SerializationException(
              "Type '"
                  + clazz.Name
                  + "' was not included in the set of types which can be deserialized by this SerializationPolicy. For security purposes, this type will not be deserialized.");
        }
      }

      /*
       * (non-Javadoc)
       * 
       * @see com.google.gwt.user.server.rpc.SerializationPolicy#validateSerialize(java.lang.String)
       */
      public override void validateSerialize(Type clazz)
      {
        if (!isInstantiable(clazz)) {
          throw new SerializationException(
              "Type '"
                  + clazz.Name
                  + "' was not included in the set of types which can be serialized by this SerializationPolicy. For security purposes, this type will not be serialized.");
        }
      }

      /**
       * Field serializable types are primitives and types on the whitelist.
       */
      private Boolean isFieldSerializable(Type clazz) {
        if (clazz.IsPrimitive) {
          return true;
        }
        return whitelist.ContainsKey(clazz);
      }

      /**
       * Instantiable types are primitives and types on the whitelist which can be
       * instantiated.
       */
      private Boolean isInstantiable(Type clazz) {
          if (clazz.IsPrimitive)
          {
          return true;
        }
        Boolean instantiable = whitelist.ContainsKey(clazz) ? whitelist[clazz] : false;
        return instantiable;
      }

     }


}
